﻿#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;

class Date
{
public:
	Date(int year = 1, int month = 1, int day = 1)//构造函数
	{
		_year = year;
		_month = month;
		_day = day;
	}
	void Print()
	{
		cout << _year << "-" << _month << "-" << _day << endl;
	}

	Date(const Date& d)//拷贝构造函数
	//拷⻉构造函数的第一个参数必须是类类型对象的引⽤，使⽤传值⽅式编译器直接报错，因为语法逻辑上会引发⽆穷递归调⽤。
	//Date(Date d)传值构造会报错.
	{
		_year = d._year;
		_month = d._month;
		_day = d._day;
	}

private:
	int _year;
	int _month;
	int _day;
};

void Func1(Date d)
{
	cout << &d << endl;
	d.Print();
}
int main()
{
	Date d1(2024, 7, 12);
	d1.Print();

	// C++的规定，传值传参要调用拷贝构造,所以这⾥的d1传值传参给d要调⽤拷⻉构造完成拷⻉，传引⽤传参可以较少这⾥的拷⻉
	Func1(d1);//相当于调用两个函数,先调用拷贝构造再调用func1
	cout << &d1 << endl;

	/*Date d2(&d1);//这⾥可以完成拷⻉，但是不是拷⻉构造，只是⼀个普通的构造.d1相当于d,d2相当于this.
	d1.Print();
	d2.Print();*/

	Date d2(d1);//拷⻉构造，通过同类型的对象初始化构造，⽽不是指针
	d2.Print();
	//Date d2 = d1;这样拷贝构造也是ok的
	//d2.Print();

	return 0;
}


//举例如下:
typedef int STDataType;
class Stack
{
public:
	Stack(int n = 4)//构造函数
	{
		_a = (STDataType*)malloc(sizeof(STDataType) * n);
		if (nullptr == _a)
		{
			perror("malloc申请空间失败");
			return;
		}
		_capacity = n;
		_top = 0;
	}

	// st2(st1)
	Stack(const Stack& st)//拷贝构造(深拷贝)
	{
		cout << "Stack(const Stack& st)" << endl;

		// 需要对_a指向资源创建同样大的资源再拷贝值
		_a = (STDataType*)malloc(sizeof(STDataType) * st._capacity);
		if (nullptr == _a)
		{
			perror("malloc申请空间失败!!!");
			return;
		}
		memcpy(_a, st._a, sizeof(STDataType) * st._top);
		_top = st._top;
		_capacity = st._capacity;
	}

	void Push(STDataType x)
	{
		if (_top == _capacity)
		{
			int newcapacity = _capacity * 2;
			STDataType* tmp = (STDataType*)realloc(_a, newcapacity *
				sizeof(STDataType));
			if (tmp == NULL)
			{
				perror("realloc fail");
				return;
			}
			_a = tmp;
			_capacity = newcapacity;
		}
		_a[_top++] = x;

	}
	~Stack()//析构函数
	{
		cout << "~Stack()" << endl;
		free(_a);
		_a = nullptr;
		_top = _capacity = 0;
	}
private:
	STDataType* _a;
	size_t _capacity;
	size_t _top;
};

int main()
{
	Stack st1;
	st1.Push(1);
	st1.Push(2);

	// Stack不显示实现拷贝构造，用自动生成的拷贝构造完成浅拷贝
	// 会导致st1和st2里面的_a指针指向同一块资源，析构时会析构两次，程序崩溃,所以要使用深拷贝

	Stack st2(st1);//拷贝构造
	//Stack st2 = st1;//也是ok的
	return 0;
}


//运算符重载
class Date
{
public:
	Date(int year = 1, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}

	// d3 = d1
	/*Date& operator=(const Date& d)
	{
		_year = d._year;
		_month = d._month;
		_day = d._day;

		return *this;
	}*/

	// 拷贝构造
	Date(const Date& d)
	{
		_year = d._year;
		_month = d._month;
		_day = d._day;
	}

	// 构造,但不是拷贝构造,此时用的是指针不是别名,和上面的有区别
	Date(const Date* d)
	{
		_year = d->_year;
		_month = d->_month;
		_day = d->_day;
	}

	void Print()
	{
		cout << _year << "-" << _month << "-" << _day << endl;
	}

	//运算符重载
	bool operator==(const Date& d)//相当于是函数名
	{
		return _year == d._year
			&& _month == d._month
			&& _day == d._day;
	}

	//赋制重载拷贝
	void operator=(const Date& d)
	{
		_year = d._year;
		_month = d._month;
		_day = d._day;
	}
	//d1 + 100;
	Date operator+(int day);
	//d1 - 100;
	Date operator-(int day);
	// d1 - d2;
	int operator-(const Date& d);

private:
	int _year;
	int _month;
	int _day;
};

//bool operator==(const Date& d1, const Date& d2)//当类域里和全局都有运算符重载时,优先调用类里面的
//{
//	return d1._year == d2._year
//		&& d1._month == d2._month
//		&& d1._day == d2._day;
//}

int main()
{
	Date d1(2024, 7, 5);
	Date d2(2024, 7, 6);

	// 运算符重载函数可以显示调用
	//operator==(d1, d2);
	// 编译器会转换成 operator==(d1, d2);
	//d1 == d2;

	// 运算符重载函数可以显示调用
	d1.operator==(d2);

	// 编译器会转换成 d1.operator==(d2);
	d1 == d2;

	/*d1 + 100;
	d1 - 100;
	d1 - d2;*/

	return 0;
}


//赋值运算符重载
int main()
{
	Date d1(2024, 7, 5);
	Date d2(2024, 7, 6);

	// 赋值重载拷贝,(已经存在的两个对象d1,d2)
	d1 = d2;

	// 拷贝构造
	Date d3(d2);
	Date d4 = d2;

	d4 = d3 = d1;//连续赋值

	int i, j, k;
	i = j = k = 1;

	return 0;
}